package com.clt.web.common;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.clt.web.service.IWeixinKitService;
import com.clt.web.utils.DateUtil;
import com.clt.web.utils.SHA1Util;


/**
 * 微信常用的基本API
 *
 */
public class WeChat {

    private static final String ACCESSTOKEN_URL  = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
    private static final String JSAPI_TICKET     = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=";
    
	private static final Logger log = Logger.getLogger(WeChat.class);
    
    /**
     * 签名检查
     *
     * @param token
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static Boolean checkSignature(String token, String signature, String timestamp, String nonce) {
    	List<String> params = new ArrayList<String>();
        params.add(token);
        params.add(timestamp);
        params.add(nonce);
        Collections.sort(params,new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        String temp = params.get(0)+params.get(1)+params.get(2);
        return SHA1Util.encode(temp).equals(signature);
    }

    /**
     * 获取access_token（有效期7200秒)
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> getAccessToken() throws Exception {
    	IWeixinKitService weixinKit = WeixinKitFactory.getWeixinKit();
        String jsonStr = HttpKit.get(ACCESSTOKEN_URL.concat("&appid=") + weixinKit.getAppid() + "&secret=" + weixinKit.getAppsecret());
        Map<String, Object> map = JSONObject.parseObject(jsonStr);
        log.info("获取到access_token map为:"+ map);
        return map;
    }
    
    /**
     * 获得jsapi_ticket（有效期7200秒) 
     *
     * @param accessToken
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * @throws IOException
     * @throws NoSuchProviderException
     */
    public static String getTicket() throws InterruptedException, ExecutionException, NoSuchAlgorithmException, KeyManagementException, IOException, NoSuchProviderException {
    	IWeixinKitService weixinKit = WeixinKitFactory.getWeixinKit();
		String accessToken = weixinKit.getAccessToken();
		String accessTicket = null;
		try {
			//获取缓存的access_ticket
			accessTicket = WeiXinPropertiesUtil.getAccessTicket();
			String lastTime = WeiXinPropertiesUtil.getTicketTime();
			log.info("读取配置access_ticket={"+accessTicket+"},上次同步时间={"+lastTime+"}");
			Date accessExpires = DateUtil.parseDateTime(lastTime);
			Date now = new Date();
			if (now.getTime() > accessExpires.getTime()) {
				log.info("获取access_ticket(jsapi),判断出已过期");
				// 获取access_ticket
				String jsonStr = null;
				try {
					jsonStr = HttpKit.get(JSAPI_TICKET.concat(accessToken));
					accessTicket = JSONObject.parseObject(jsonStr).get("ticket").toString();
				} catch (Exception e) {
					throw new Exception("获取access_ticket失败" + e.getMessage()+","+jsonStr);
				}
				accessExpires = new Date(now.getTime() + 7200000);
				String nextTime = DateUtil.formatDateTime(accessExpires);
				log.info("更新配置access_ticket={"+accessTicket+"},更新上次同步时间={"+nextTime+"}");
				// 更新accessTicket和TicketTime
				WeiXinPropertiesUtil.setAccessTicket(accessTicket);
				WeiXinPropertiesUtil.setTicketTime(nextTime);
			} else {
				log.info("获取access_ticket,判断出未过期");
			}
		} catch (Exception e) {
			log.error("获取access_ticket失败{"+e.getMessage()+"}");
		}
    	log.info("获取到ticket为:"+ accessTicket);
        return accessTicket;
    }

    /**
     * 生成jsApi的签名信息
     *
     * @param jsapiTicket
     * @param url
     * @return
     */
    public static Map<String, String> jsApiSign(String jsapiTicket, String url) {
        return sign(jsapiTicket, url);
    }
    
    /**
	 * js高级接口签名
	 * @param jsapi_ticket
	 * @param url
	 * @return
	 */
    public static Map<String, String> sign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = UUID.randomUUID().toString();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    /**
     * byte转Hex
     * @param hash
     * @return
     */
    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }
}
